using System;
using System.Collections.Generic;
using System.Text;
using Ares.PacketHandlers;

namespace cb0tServer
{
    class FileBrowseHelpers
    {
        public static void ProcessLinkedBrowseRequest(LinkClient link, String requester, UserObject tUser, ushort ident, byte mime, bool compress)
        {
            if (tUser == null) // no such user
            {
                link.SendOutboundPacket(ServerOutboundPackets.LinkBrowseError(requester, ident));
                return;
            }

            SharedFileObject[] files = tUser.GetFiles();
            List<byte> compressed_packets = new List<byte>();

            if (files == null) // no files
            {
                link.SendOutboundPacket(ServerOutboundPackets.LinkBrowseStart(requester, ident, 0));
                link.SendOutboundPacket(ServerOutboundPackets.LinkBrowseEnd(requester, ident));
                return;
            }

            if (mime == 255) // send all files
            {
                link.SendOutboundPacket(ServerOutboundPackets.LinkBrowseStart(requester, ident, (ushort)files.Length));

                foreach (SharedFileObject f in files)
                {
                    byte[] p = ServerOutboundPackets.BrowseItemPacket(ident, f);

                    if (compress)
                    {
                        compressed_packets.AddRange(ServerOutboundPackets.LinkDataToTarget(requester, p));

                        if (compressed_packets.Count > 800)
                        {
                            p = ServerOutboundPackets.CompressPacket(compressed_packets.ToArray());
                            compressed_packets.Clear();
                            link.SendOutboundPacket(p);
                        }
                    }
                    else
                    {
                        link.SendOutboundPacket(ServerOutboundPackets.LinkDataToTarget(requester, p));
                    }
                }

                if (compress)
                {
                    if (compressed_packets.Count > 0)
                    {
                        byte[] p = ServerOutboundPackets.CompressPacket(compressed_packets.ToArray());
                        compressed_packets.Clear();
                        link.SendOutboundPacket(p);
                    }
                }

                link.SendOutboundPacket(ServerOutboundPackets.LinkBrowseEnd(requester, ident));
            }
            else // specific file type
            {
                link.SendOutboundPacket(ServerOutboundPackets.LinkBrowseStart(requester, ident, FileCount(files, mime)));

                foreach (SharedFileObject f in files)
                {
                    if (f.type == mime)
                    {
                        byte[] p = ServerOutboundPackets.BrowseItemPacket(ident, f);

                        if (compress)
                        {
                            compressed_packets.AddRange(ServerOutboundPackets.LinkDataToTarget(requester, p));

                            if (compressed_packets.Count > 800)
                            {
                                p = ServerOutboundPackets.CompressPacket(compressed_packets.ToArray());
                                compressed_packets.Clear();
                                link.SendOutboundPacket(p);
                            }
                        }
                        else
                        {
                            link.SendOutboundPacket(ServerOutboundPackets.LinkDataToTarget(requester, p));
                        }
                    }
                }

                if (compress)
                {
                    if (compressed_packets.Count > 0)
                    {
                        byte[] p = ServerOutboundPackets.CompressPacket(compressed_packets.ToArray());
                        compressed_packets.Clear();
                        link.SendOutboundPacket(p);
                    }
                }

                link.SendOutboundPacket(ServerOutboundPackets.LinkBrowseEnd(requester, ident));
            }
        }

        public static SharedFileObject CreateFileObject(AresDataPacket packet)
        {
            byte add_share_file_type = packet.ReadByte();
            uint add_share_file_size = packet.ReadInt32();
            ushort add_share_search_size = packet.ReadInt16();
            byte[] tmp = packet.ReadBytes((int)add_share_search_size);
            String add_share_search_words = Encoding.UTF8.GetString(tmp).ToUpper();
            byte[] add_share_content = packet.ReadBytes();

            packet = new AresDataPacket(add_share_content);

            switch (add_share_file_type)
            {
                case 0:
                    //other
                    if (!CoreSettings.allow_other)
                        return null;

                    packet.SkipBytes(20);
                    break;

                case 1:
                    //music
                    if (!CoreSettings.allow_audio)
                        return null;

                    packet.SkipBytes(24);
                    break;

                case 2:
                    //image
                    if (!CoreSettings.allow_images)
                        return null;

                    packet.SkipBytes(25);
                    break;

                case 3:
                    //software
                    if (!CoreSettings.allow_software)
                        return null;

                    packet.SkipBytes(20);
                    break;

                case 5:
                    //video
                    if (!CoreSettings.allow_video)
                        return null;

                    packet.SkipBytes(26);
                    break;

                case 6:
                    //document
                    if (!CoreSettings.allow_documents)
                        return null;

                    packet.SkipBytes(20);
                    break;

                case 7:
                    //image
                    if (!CoreSettings.allow_images)
                        return null;

                    packet.SkipBytes(25);
                    break;
            }

        //    String add_share_file_name = packet.ReadString();
        //    add_share_file_name = FormatFileName(add_share_file_name.Split(
        //        new String[] { "" }, StringSplitOptions.None)[0]);

            String add_share_file_name = FileItemFormatName(packet.ReadBytes());

            return new SharedFileObject(add_share_file_type, add_share_file_size,
                add_share_content, add_share_file_name, add_share_search_words);
        }

        private static String FileItemFormatName(byte[] data)
        {
            List<byte> buf1 = new List<byte>(data);
            int i = buf1.IndexOf(1);

            if (i == -1)
                return String.Empty;

            byte[] buf2 = buf1.GetRange(0, i - 1).ToArray();
            return Encoding.UTF8.GetString(buf2);
        }

        public static void ProcessSearchRequest(UserObject userobj, AresDataPacket packet)
        {
            ushort id = packet.ReadInt16();
            packet.SkipByte();
            byte type = packet.ReadByte();
            ushort search_len = packet.ReadInt16();
            byte[] tmp = packet.ReadBytes(search_len);
            String search_words = Encoding.UTF8.GetString(tmp).ToUpper();
            List<byte> compressed_packets = new List<byte>();

            foreach (UserObject tUser in UserPool.Users)
            {
                if (tUser.IsSet())
                {
                    if (tUser.logged_in)
                    {
                        if (tUser.browse)
                        {
                            SharedFileObject[] files = tUser.GetFiles();

                            if (files != null)
                            {
                                if (type == 0 || type == 255) // searching all files
                                {
                                    for (int i = 0; i < files.Length; i++)
                                    {
                                        if (files[i].search.IndexOf(search_words) > -1)
                                        {
                                            byte[] p = ServerOutboundPackets.SearchItemPacket(id, tUser, files[i]);

                                            if (userobj.supports_compression)
                                            {
                                                compressed_packets.AddRange(p);

                                                if (compressed_packets.Count > 800)
                                                {
                                                    p = ServerOutboundPackets.CompressPacket(compressed_packets.ToArray());
                                                    compressed_packets.Clear();
                                                    userobj.SendOutboundPacket(p);
                                                }
                                            }
                                            else
                                            {
                                                userobj.SendOutboundPacket(p);
                                            }
                                        }
                                    }
                                }
                                else // searching specific file type
                                {
                                    if (type == 8) type = 0; // sort out "other" file confusion

                                    for (int i = 0; i < files.Length; i++)
                                    {
                                        if (files[i].type == type)
                                        {
                                            if (files[i].search.IndexOf(search_words) > -1)
                                            {
                                                byte[] p = ServerOutboundPackets.SearchItemPacket(id, tUser, files[i]);

                                                if (userobj.supports_compression)
                                                {
                                                    compressed_packets.AddRange(p);

                                                    if (compressed_packets.Count > 800)
                                                    {
                                                        p = ServerOutboundPackets.CompressPacket(compressed_packets.ToArray());
                                                        compressed_packets.Clear();
                                                        userobj.SendOutboundPacket(p);
                                                    }
                                                }
                                                else
                                                {
                                                    userobj.SendOutboundPacket(p);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            if (userobj.supports_compression)
            {
                if (compressed_packets.Count > 0)
                {
                    byte[] p = ServerOutboundPackets.CompressPacket(compressed_packets.ToArray());
                    compressed_packets.Clear();
                    userobj.SendOutboundPacket(p);
                }
            }

            userobj.SendOutboundPacket(ServerOutboundPackets.SearchEndPacket(id));
        }

        public static void ProcessBrowseRequest(LinkClient link, UserObject userobj, AresDataPacket packet)
        {
            ushort id = packet.ReadInt16();
            byte type = packet.ReadByte();
            String target = packet.ReadString();

            if (target == CoreSettings.room_bot)
            {
                SharedFileObject botfile = new SharedFileObject();
                botfile.search = CoreSettings.room_bot;
                botfile.size = 69;
                botfile.type = 0;

                userobj.SendOutboundPacket(ServerOutboundPackets.BrowseStartPacket(id, 1));
                botfile.name = "sb0t 4.64";
                botfile.content = ServerOutboundPackets.BrowseBotFile(botfile);
                userobj.SendOutboundPacket(ServerOutboundPackets.BrowseItemPacket(id, botfile));
                userobj.SendOutboundPacket(ServerOutboundPackets.BrowseEndPacket(id));

                return;
            }

            UserObject tUser = UserPool.GetUserByName(target);

            if (tUser == null) // user offline
            {
                if (link.IsLinking()) // could be a linked user...
                {
                    LinkedUserObject lUser = link.GetUser(target);

                    if (lUser == null) // user offline
                    {
                        userobj.SendOutboundPacket(ServerOutboundPackets.BrowseFailPacket(id));
                    }
                    else // it is a linked user
                    {
                        if (type == 0) type = 255; // all files
                        if (type == 8) type = 0; // others
                        link.SendOutboundPacket(ServerOutboundPackets.LinkBrowseRequest(userobj, lUser, id, type));
                        return;
                    }
                }
                else // user offline
                {
                    userobj.SendOutboundPacket(ServerOutboundPackets.BrowseFailPacket(id));
                }
            }
            else
            {
                SharedFileObject[] files = tUser.GetFiles();
                List<byte> compressed_packets = new List<byte>();

                if (files == null) // target says he is sharing files but isn't really
                {
                    userobj.SendOutboundPacket(ServerOutboundPackets.BrowseFailPacket(id));
                    return;
                }

                if (type == 0 || type == 255) // browsing all files
                {
                    userobj.SendOutboundPacket(ServerOutboundPackets.BrowseStartPacket(id, (ushort)files.Length));

                    for (int i = 0; i < files.Length; i++)
                    {
                        byte[] p = ServerOutboundPackets.BrowseItemPacket(id, files[i]);

                        if (userobj.supports_compression)
                        {
                            compressed_packets.AddRange(p);

                            if (compressed_packets.Count > 800)
                            {
                                p = ServerOutboundPackets.CompressPacket(compressed_packets.ToArray());
                                compressed_packets.Clear();
                                userobj.SendOutboundPacket(p);
                            }
                        }
                        else
                        {
                            userobj.SendOutboundPacket(p);
                        }
                    }

                    if (userobj.supports_compression)
                    {
                        if (compressed_packets.Count > 0)
                        {
                            byte[] p = ServerOutboundPackets.CompressPacket(compressed_packets.ToArray());
                            compressed_packets.Clear();
                            userobj.SendOutboundPacket(p);
                        }
                    }

                    userobj.SendOutboundPacket(ServerOutboundPackets.BrowseEndPacket(id));
                }
                else // browsing a specific file type
                {
                    if (type == 8) type = 0; // sort out "other" file confusion

                    userobj.SendOutboundPacket(ServerOutboundPackets.BrowseStartPacket(id, FileCount(files, type)));

                    for (int i = 0; i < files.Length; i++)
                    {
                        if (files[i].type == type)
                        {
                            byte[] p = ServerOutboundPackets.BrowseItemPacket(id, files[i]);

                            if (userobj.supports_compression)
                            {
                                compressed_packets.AddRange(p);

                                if (compressed_packets.Count > 800)
                                {
                                    p = ServerOutboundPackets.CompressPacket(compressed_packets.ToArray());
                                    compressed_packets.Clear();
                                    userobj.SendOutboundPacket(p);
                                }
                            }
                            else
                            {
                                userobj.SendOutboundPacket(p);
                            }
                        }
                    }

                    if (userobj.supports_compression)
                    {
                        if (compressed_packets.Count > 0)
                        {
                            byte[] p = ServerOutboundPackets.CompressPacket(compressed_packets.ToArray());
                            compressed_packets.Clear();
                            userobj.SendOutboundPacket(p);
                        }
                    }

                    userobj.SendOutboundPacket(ServerOutboundPackets.BrowseEndPacket(id));
                }
            }
        }

        private static String FormatFileName(String input)
        {
            try
            {
                int last = (int)char.Parse(input.Substring(input.Length - 1).ToUpper());

                if (last == 51 || (last >= 65 && last <= 90)) return input;

                return input.Substring(0, input.Length - 1);
            }
            catch { }

            return input;
        }

        private static ushort FileCount(SharedFileObject[] files, byte filetype)
        {
            ushort counter = 0;

            for (int i = 0; i < files.Length; i++)
            {
                if (files[i].type == filetype)
                {
                    counter++;
                }
            }

            return counter;
        }
    }
}
